package rs.udd.web.controller;

import static rs.udd.service.util.SecurityUtil.ADMIN_ROLE_ONLY;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import rs.udd.constants.UddMessages;
import rs.udd.exceptions.UddException;
import rs.udd.model.Advert;
import rs.udd.model.Advertiser;
import rs.udd.model.Agent;
import rs.udd.service.AdminService;
import rs.udd.service.AdvertService;
import rs.udd.service.AdvertiserService;
import rs.udd.service.AgentService;
import rs.udd.service.MailService;
import rs.udd.service.dto.advert.DeleteAdvertDto;
import rs.udd.service.dto.advertiser.AdvertiserEditDto;
import rs.udd.service.dto.advertiser.AdvertiserViewDto;
import rs.udd.service.dto.agent.AgentEditDto;
import rs.udd.service.dto.agent.AgentViewDto;
import rs.udd.service.dto.user.AdminChangePasswordDto;
import rs.udd.service.dto.user.DeleteUserDto;
import rs.udd.service.mappings.AdvertiserMapping;
import rs.udd.service.mappings.AgentMapping;
import rs.udd.web.binding.DateBinder;

@Controller
@RequestMapping({ "admins", "/admins", "/admins/" })
public class AdminController {

	private static final Logger LOGGER = LogManager.getLogger(AdminController.class);
	
	@Autowired
	private MailService mailService;
	
	@Autowired
	private AdminService adminService;
	
	@Autowired
	private AgentService agentService;
	
	@Autowired
	private AdvertiserService advertiserService;
	
	@Autowired
	private AdvertService advertService;
	
	@Autowired
	private DateBinder dateBinder;

	@InitBinder
	public void initBind(WebDataBinder binder) {
		binder.registerCustomEditor(Date.class, dateBinder);
	}

	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/delete-advert", method = RequestMethod.POST)
	public String deleteAdvert(@ModelAttribute("deleteAdvertDto") DeleteAdvertDto dto) throws UddException {
	
		Advert advert = advertService.findOne(dto.getId());
		Advertiser advertiser = advert.getAdvertiser();
		
		advertService.delete(dto.getId());

		LOGGER.info("Deleting advert with id: " + dto.getId());
		
		String message = UddMessages.MESSAGE_EMAIL_GREETING.replace("[username]", advertiser.getUsername()) + "\n\n" + UddMessages.MESSAGE_EIMAIL_ADVERT_DELETION_TEXT + "\n\n\n" + UddMessages.MESSAGE_EMAIL_VALEDICTION;		
		message = message.replace("[advertTitle]", advert.getTitle());
		message = message.replace("[reason]", dto.getReason());
		
		mailService.sendMail(advertiser.getEmail(), UddMessages.MESSAGE_EIMAIL_ADVERT_DELETION_SUBJECT, message);
		
		return "redirect:/advertisers/view/"+advertiser.getId();
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/view-all-agents", method = RequestMethod.GET)
	public String viewAllAgents(Model model) {
		LOGGER.info("Viewing all agents...");
		
		List<Agent> allAgents = adminService.getAllAgents();
		model.addAttribute("agents", allAgents);
		return "admin/viewAllAgents";
	}

	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/view-all-advertisers", method = RequestMethod.GET)
	public String viewAllAdvertisers(Model model) {
		LOGGER.info("Viewing all advertisers...");
		
		List<Advertiser> advertisers = adminService.getAllAdvertisers();
		model.addAttribute("advertisers", advertisers);
		model.addAttribute("deleteUserDto", new DeleteUserDto());	// TODO: Nikola - move this to view advertiser page when it's finished
		return "admin/viewAllAdvertisers";
	}

	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/view-all-inactive-advertisers", method = RequestMethod.GET)
	public String viewAllInactiveAdvertisers(Model model) {
		List<Advertiser> inactiveAdvertisers = adminService.getAllInactiveAdvertisers();
		LOGGER.info("Viewing all inactive advertisers... (" + inactiveAdvertisers.size() + ")");
		model.addAttribute("inactiveAdvertisers", inactiveAdvertisers);
		model.addAttribute("deleteUserDto", new DeleteUserDto());	// TODO: Nikola - move this to view advertiser page when it's finished
		return "admin/viewAllInactiveAdvertisers";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/delete-agent", method = RequestMethod.POST)
	public String deleteAgent(@Valid @ModelAttribute("deleteUserDto") DeleteUserDto dto, BindingResult result) throws UddException {
		LOGGER.info("Deleting agent with id " + dto.getId());
		adminService.deleteAgent(dto);
		return "redirect:/home";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/delete-advertiser", method = RequestMethod.POST)
	public String deleteAdvertiser(@ModelAttribute("deleteUserDto") DeleteUserDto dto) throws UddException {
		LOGGER.info("Deleting advertiser with id " + dto.getId());
		adminService.deleteAdvertiser(dto);
		return "redirect:/home";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/change-agent-password/{id}", method = RequestMethod.GET)
	public String changeAgentsPassword(@PathVariable("id") Long id, Model model) {
		AdminChangePasswordDto dto = new AdminChangePasswordDto();
		dto.setUsersId(id);
		model.addAttribute("adminChangePasswordDto", dto);
		return "/admin/changeAgentsPassword";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/change-advertiser-password/{id}", method = RequestMethod.GET)
	public String changeAdvertisersPassword(@PathVariable("id") Long id, Model model) {
		AdminChangePasswordDto dto = new AdminChangePasswordDto();
		dto.setUsersId(id);
		model.addAttribute("adminChangePasswordDto", dto);
		return "/admin/changeAdvertisersPassword";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/change-agent-password", method = RequestMethod.POST)
	public String changeAgentPassword(@Valid @ModelAttribute("adminChangePasswordDto") AdminChangePasswordDto dto) {
		LOGGER.info("Admin changing agents password...");
		adminService.changeAgentPassword(dto);
		return "/home";
	}

	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/change-advertiser-password", method = RequestMethod.POST)
	public String changeAdvertiserPassword(@Valid @ModelAttribute("adminChangePasswordDto") AdminChangePasswordDto dto) {
		LOGGER.info("Admin changing advertisers password...");
		adminService.changeAdvertiserPassword(dto);
		return "/home";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/viewAllAdvertisers", method = RequestMethod.GET)
	public String getAllAdvertisers(Model model, HttpServletResponse resp) throws UddException {
		
		
		List<Advertiser> advertisers = advertiserService.findAll();
		
		model.addAttribute("allAdvertisers", advertisers);

		return "/admin/viewAdvertisers";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/deleteAdvertiser/{id}", method = RequestMethod.GET)
	public String deleteAdvertiser(@PathVariable Long id, Model model, HttpServletResponse resp) throws UddException {
		
		advertiserService.delete(id);

		return "redirect:/admins/viewAllAdvertisers";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/prepare-edit-advertiser/{id}", method = RequestMethod.GET)
	public String editAdvertiserGet(@PathVariable Long id, HttpSession session, Model model,
			Authentication authentication) throws UddException {

		LOGGER.info("Request to edit advertiser...");
		
		Advertiser advertiser = advertiserService.findOne(id);

		AdvertiserViewDto editAdvertiserDto = AdvertiserMapping.viewToEdit(advertiser);
		model.addAttribute("editedAdvertiser", editAdvertiserDto);

		return "/admin/editAdvertiser";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/edit-advertiser", method = RequestMethod.POST)
	public String editAdvertiserPost(@Valid @ModelAttribute("editedAdvertiser") AdvertiserEditDto dto, BindingResult result, Model model, HttpSession session,
			Authentication authentication) throws UnsupportedEncodingException, UddException {
		
		if (result.hasErrors()) {
			LOGGER.error("Binding error," + result);List<Advertiser> advertisers = adminService.getAllAdvertisers();
			model.addAttribute("advertisers", advertisers);
			model.addAttribute("deleteUserDto", new DeleteUserDto());
			return "admin/viewAllAdvertisers";
		}
				
		advertiserService.edit(dto);

		LOGGER.info("Editing advertiser...");
		
		model.addAttribute("infoMessage", UddMessages.INFO_ADVERTISER_SUCCESSFULLY_EDITED);
		
		return "home";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/prepare-edit-agent/{id}", method = RequestMethod.GET)
	public String editAgentGet(@PathVariable Long id, HttpSession session, Model model,
			Authentication authentication) throws UddException {

		LOGGER.info("Request to edit advertiser...");
		
		Agent agent = agentService.findOne(id);
		
		AgentViewDto editAgentDto = AgentMapping.viewToEdit(agent);
		model.addAttribute("editedAgent", editAgentDto);

		return "/admin/editAgent";
	}
	
	@PreAuthorize(ADMIN_ROLE_ONLY)
	@RequestMapping(value = "/edit-agent", method = RequestMethod.POST)
	public String handleEditPost(@Valid @ModelAttribute("editedAgent") AgentEditDto dto, BindingResult result, Model model,
			Authentication authentication) throws UddException {
		
		if (result.hasErrors()) {
			LOGGER.error("Binding error," + result);
			List<Agent> allAgents = adminService.getAllAgents();
			model.addAttribute("agents", allAgents);
			return "admin/viewAllAgents";
		}
				
		agentService.edit(dto);

		LOGGER.info("Editing agent...");
		
		model.addAttribute("infoMessage", UddMessages.INFO_AGENT_SUCCESSFULLY_EDITED);
		
		return "home";
	}
	
}
